package org.apache.ocean.util;

import java.util.regex.Pattern;

public class Base26 implements Comparable {

	private static final String REGEX = "[A-Z]";
	private static final String TOKEN_REGEX = "[A-Z]";

	public static final int BASE = 260;
	public static final int MIN_CODE = 0;
	public static final int MAX_CODE = BASE * BASE * BASE - 1;

	private String code;
	private int hash;

	public Base26(String code) {
		//if (Pattern.matches(REGEX, code)) {
			this.code = code;
			this.hash = 0;
			for (int i = 0, m = BASE * BASE; i < code.length(); i++, m /= BASE) {
				this.hash = this.hash + m
						* tokenValue(code.substring(i, i+1));
			}

		//} else {
			//throw new IllegalArgumentException("Invalid Postal Code: " + code);
		//}
	}

	private static int tokenValue(String token) {
		if (Pattern.matches(TOKEN_REGEX, token)) {
			return ((int) token.charAt(0) - (int) 'A') * 10;
		} else {
			throw new IllegalArgumentException("Invalid Token: " + token);
		}
	}

	private static String valueToToken(int value) {
		if (value < BASE && value >= 0) {
			char letter = (char) (value / 10 + 'A');
			return new String(new char[] { letter });
		} else {
			throw new IllegalArgumentException("Invalid value: " + value);
		}
	}

	public static String hashToCode(int hash) {
		if (hash <= MAX_CODE && hash >= MIN_CODE) {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < 3; i++) {
				int tok = hash % BASE;
				sb.insert(0, valueToToken(tok));
				hash -= tok;
				hash /= BASE;
			}
			return sb.toString();
		} else {
			throw new IllegalArgumentException("Invalid hash: " + hash);
		}
	}

	public Base26 increment() {
		if (this.hash == MAX_CODE) {
			return new Base26(hashToCode(MIN_CODE));
		} else {
			return new Base26(hashToCode(this.hash + 1));
		}
	}

	public Base26 decrement() {
		if (this.hash == MIN_CODE) {
			return new Base26(hashToCode(MAX_CODE));
		} else {
			return new Base26(hashToCode(this.hash - 1));
		}
	}

	public int hashCode() {
		return hash;
	}

	public boolean equals(Object obj) {
		if (obj instanceof Base26) {
			return this.hash == ((Base26) obj).hash;
		} else {
			return false;
		}
	}

	public String toString() {
		return code;
	}

	public int compareTo(Object obj) {
		return this.hash - ((Base26) obj).hash;
	}

	public static void main(String[] args) {
		Base26 pc1 = new Base26("AA");
		Base26 pc2 = new Base26("ZZ");
		for (int i = pc1.hashCode(); i <= pc2.hashCode(); i++) {
			System.out.println(pc1);
			pc1 = pc1.increment();
		}
	}
}
